'use strict';

const RouterService = require('../base');
const config = require("../../../config/wx");
const path = require("path");
const fs = require("fs");
const crypto = require("crypto");
const { BalanceLogTypeEnum } = require("../../utils/enum");

function generateNonceStr(len) {
    let data = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
    let str = "";
    for (let i = 0; i < len; i++) {
        str += data.charAt(Math.floor(Math.random() * data.length));
    }
    return str;
}

function generateWithdrawNo() {
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, '0');
    const day = String(now.getDate()).padStart(2, '0');
    const timestamp = String(now.getTime()).slice(-6);
    const random = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
    return `WD${year}${month}${day}${timestamp}${random}`;
}

class BalanceRecordService extends RouterService {
    static get modelName() {
        return 'Business.BalanceRecord';
    }
    getPageInclude() {
        return [
            {
                model: this.ctx.model.Business.User,
                as: 'user'
            }
        ]
    }

    async withdraw(data) {
        const { user_id, amount } = data;
        
        // 验证参数
        if (!user_id || !amount) {
            this.ctx.throw(400, '缺少必要参数');
        }
        
        if (amount < 0.1) {
            this.ctx.throw(400, '提现金额不能少于0.1元');
        }

        // 用户判空
        const user = await this.ctx.model.Business.User.findByPk(user_id);
        if (!user) {
            this.ctx.throw(400, '用户不存在');
        }
        if (!user.openid) {
            this.ctx.throw(400, '用户未绑定微信');
        }

        // 验证余额
        if (parseFloat(user.balance) < amount) {
            this.ctx.throw(400, '余额不足');
        }

        // 验证每日提现限额
        const todayTotal = await this.getTodayWithdrawTotal(user_id);
        if (todayTotal + amount > 2000) {
            this.ctx.throw(400, '超出每日提现限额2000元');
        }

        // 生成提现单号
        const withdrawNo = generateWithdrawNo();
        
        // 创建事务
        const transaction = await this.ctx.model.transaction();
        try {
            // 1. 先扣减用户余额
            await this.ctx.model.Business.User.update({
                balance: this.ctx.model.Sequelize.literal(`balance - ${amount}`)
            }, {
                where: { id: user_id },
                transaction
            });

            // 2. 创建提现记录
            const balanceRecord = await this.ctx.model.Business.BalanceRecord.create({
                user_id: user_id,
                user_type: user.user_type,
                amount: -amount, // 负数表示提现
                type: BalanceLogTypeEnum.WITHDRAW,
                description: `提现申请，单号：${withdrawNo}`,
                status: 0,
                out_bill_no: withdrawNo
            }, { transaction });

            // 3. 调用微信提现接口
            const transferResult = await this.callWxTransfer({
                mchId: config.mch_id,
                appId: config.appid,
                out_bill_no: withdrawNo,
                openid: user.openid,
                transfer_amount: Math.ceil(amount * 100), // 转换为分
                transfer_remark: '余额提现'
            });

            // 4. 如果微信调用成功，提交事务
            await transaction.commit();
            
            // 返回小程序需要的数据格式
            return {
                mchId: config.mch_id,
                appId: config.appid,
                package: transferResult.transfer_detail_no || transferResult.bill_no || '',
                withdraw_no: withdrawNo,
                amount: amount,
                status: '提现申请已提交'
            }

        } catch (error) {
            // 回滚事务
            await transaction.rollback();
            this.ctx.logger.error('提现失败:', error);
            throw new Error(error.message || '提现申请失败');
        }
    }

    /**
     * 调用微信提现接口
     */
    async callWxTransfer(params) {
        const { out_bill_no, openid, transfer_amount, transfer_remark } = params;
        
        const transferParams = {
            appid: config.appid,
            out_bill_no: out_bill_no,
            transfer_scene_id: "1000", // 1000-服务商代发场景
            openid: openid,
            transfer_amount: transfer_amount,
            transfer_remark: transfer_remark,
            notify_url: config.notify_url_transfer, // 提现回调地址
            user_recv_perception: "余额提现",
            transfer_scene_report_infos: [
                {
                    "info_type" :   "安澜云旅",
                    "info_content" : "余额提现"
                },
                {
                    "info_type" : "奖励说明",
                    "info_content" : "余额提现"
                }
            ]
        };

        const timeStamp = Math.floor(new Date().getTime() / 1000);
        const nonceStr = generateNonceStr(32);
        
        const Authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${config.mch_id}",nonce_str="${nonceStr}",signature="${this.createTransferSign('POST',
            '/v3/fund-app/mch-transfer/transfer-bills',
            timeStamp,
            nonceStr,
            transferParams
        )}",timestamp="${timeStamp}",serial_no="${config.serial_no}"`;

        try {
            const transferRes = await this.ctx.curl('https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills', {
                method: "POST",
                data: transferParams,
                headers: {
                    Authorization: Authorization,
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                    'Wechatpay-Serial': config.serial_no
                },
                dataType: 'json'
            });

            if (transferRes.status === 200) {
                return transferRes.data;
            } else {
                throw new Error(transferRes.data.message || '微信提现接口调用失败');
            }
        } catch (error) {
            this.ctx.logger.error('微信提现接口调用失败:', error);
            throw new Error('微信提现接口调用失败: ' + (error.message || '网络错误'));
        }
    }

    /**
     * 生成微信提现签名
     */
    createTransferSign(method, url, timestamp, nonce_str, params) {
        // 签名串
        let signStr = `${method}\n${url}\n${timestamp}\n${nonce_str}\n${JSON.stringify(params)}\n`;
        
        // 读取API证书文件内容
        const filepath = path.join('app', '/public/apiclient_key.pem');
        let cert = fs.readFileSync(filepath, "utf-8");
        
        // 创建使用 RSA 算法和 SHA-256 散列算法的签名对象
        let sign = crypto.createSign("RSA-SHA256");
        sign.update(signStr);
        return sign.sign(cert, "base64");
    }

    /**
     * 获取用户今日提现总金额
     */
    async getTodayWithdrawTotal(user_id) {
        const today = new Date();
        const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate());
        const endOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1);

        const result = await this.ctx.model.Business.BalanceRecord.findOne({
            where: {
                user_id: user_id,
                type: BalanceLogTypeEnum.WITHDRAW,
                create_time: {
                    [this.ctx.model.Sequelize.Op.gte]: startOfDay,
                    [this.ctx.model.Sequelize.Op.lt]: endOfDay
                }
            },
            attributes: [
                [this.ctx.model.Sequelize.fn('SUM', this.ctx.model.Sequelize.fn('ABS', this.ctx.model.Sequelize.col('amount'))), 'total']
            ],
            raw: true
        });
        return result.total || 0
    }
}

module.exports = BalanceRecordService;
